#ifndef CURLING_RINK_INCLUDED
#define CURLING_RINK_INLCUDED

#include <vector>
#include <boost/shared_ptr.hpp>
#include "config.hpp"

namespace curling {

class stone;

/**
 * Rink listeners. Communicates events happening to/in the rink.
 */
class rink_listener_t
{
public:
  
  rink_listener_t();
  virtual ~rink_listener_t();
  
  /**
   * Collision between stone and wall.
   * \param impact_velocity Magnitude of impact vector.
   */
  virtual void stone_wall_collision(
    boost::shared_ptr<stone> s,
    double impact_velocity ) = 0;
    
  /**
   * Collision between stone and stone.
   * \param impact_velocity Sum of magnitude of impact vectors. If stone 1 has
   * velocity v1 and stone 2 velocity v2 and stone 1 and stone 2 is travelling
   * directly towards each other the impact_velocity will be |v1|+|v2|.
   */
  virtual void stone_stone_collision(
    boost::shared_ptr<stone> s1,
    boost::shared_ptr<stone> s2,
    double impact_velocity ) = 0;
};

/**
 * Default rink measures from south walk.
 */
namespace default_rink {
  const double width = 4.75;
  const double length = 44.5;
  const double hack = 1.22;
  const double circle0_radius = 0.15;//innermost circle
  const double circle1_radius = 0.61;
  const double circle2_radius = 1.22;
  const double circle3_radius = 1.83;
  const double foot_line = 0.0;
  const double tee_line = hack + 3.66;
  const double back_line = length - tee_line + circle3_radius;
  const double hog_line = back_line - circle3_radius - 6.40;
  const double circle = back_line - circle3_radius;
}

/**
 * For more information, see WCFRulesofPlayandCompetition.pdf in /doc.
 */
class rink
{
public:
  
  typedef std::vector< boost::shared_ptr<stone> > stone_container;
  typedef stone_container::iterator stone_iterator;
  
  /** Construct rink. */
  rink();
  /** Destructor. */
  ~rink();
  
  double width() const;
  double length() const;
  double hack() const;
  double foot_line() const;
  double tee_line() const;
  double back_line() const;
  double hog_line() const;
  double circle() const;//circle position on y-axis
  double circle0_radius() const;
  double circle1_radius() const;
  double circle2_radius() const;
  double circle3_radius() const;
  stone_iterator begin_stones();
  stone_iterator end_stones();
  
  /** Add a stone to the rink. */
  void add_stone( boost::shared_ptr<stone> s );
  /** Remove a stone from the rink. */
  void remove_stone( boost::shared_ptr<stone> s );
  
  /** Move stones and handle collisions. */
  void simulate( double dt );
  
  void add_listener( boost::shared_ptr<rink_listener_t> listener );
  void remove_listener( boost::shared_ptr<rink_listener_t> listener );
  
private:
  
  std::vector<boost::shared_ptr<rink_listener_t> > _listeners;
  
  stone_container _stones;
  
  void handle_collisions( double dt );
};

}

#endif